import { _decorator, BoxCollider, BoxCollider2D, CCBoolean, CCString, Component, director, EPhysics2DDrawFlags, Graphics, Layers, Node, PhysicsSystem2D, RigidBody, RigidBody2D, TiledMap, UITransform, Vec2, Vec3 } from 'cc';
const { ccclass, property } = _decorator;



@ccclass('MapCollider')
export class MapCollider extends Component {
    //制定添加碰撞体组的TiledMap地图
    @property(TiledMap)
    private tiledMap: TiledMap = null;

    //是否对层级添加碰撞体
    @property(CCBoolean)
    addCollider: boolean = false;
    //对哪个层级添加碰撞体
    @property(Node)
    mapLayer: Node = null;
    //碰撞检测，是否开启
    @property(CCBoolean)
    collisionDetection: boolean = false;
    //通过canvas获取绘制碰撞体边框时生成的'PHYSICS_2D_DEBUG_DRAW'节点用以修改绘制效果
    @property(Node)
    canvas: Node = null;

    protected onLoad(): void {
        //绘制碰撞边框
        if (this.collisionDetection) {
            PhysicsSystem2D.instance.debugDrawFlags = EPhysics2DDrawFlags.Shape;
        }

    }

    start() {


        if (this.addCollider) {
            //该函数为Tiledmap地图的对应层级添加碰撞体组
            this.addMapLayerCollider();
        }



        //修改绘制需要在碰撞体添加之后绘制出默认的边框后才能进行修改。
        //修改绘制碰撞边框的图形属性，使边框绘制更清晰
        //通过setTimeout()延时修改，onload()中先绘制添加后的碰撞体，才会生成'PHYSICS_2D_DEBUG_DRAW'节点
        if (this.collisionDetection) {
            setTimeout(() => {
                const draw = this.canvas.getChildByName('PHYSICS_2D_DEBUG_DRAW');
                console.log(draw);
                const graphics = draw.getComponent(Graphics);
                graphics.lineWidth = 1;
                graphics.miterLimit = 1;
            }, 1);
        }
    }

    update(deltaTime: number) {

    }

    //该函数为Tiledmap地图的对应层级添加碰撞体组
    addMapLayerCollider() {
        let tiledSize = this.tiledMap.getTileSize();
        let layer = this.tiledMap.getLayer(this.mapLayer.name);
        let layerSize = layer.getLayerSize();

        //将层级节点的位置锚点anchorPoint设置为（0,0）才能与后面getTiledTileAt()获取Tiled节点时的锚点位置匹配
        //Cocos中Tiledmap的层级节点默认anchorPoint为(0.5 , 0.5)，本来在中心
        //但是getTiledTileAt()获取Tiled节点时会将层级锚点位置（即原来的中心位置）作为左下为锚点生成
        //也就是说getTiledTileAt()整个生成逻辑是将左下角作为生成锚点
        const layerUITransform = layer.node.getComponent(UITransform);
        layerUITransform.anchorPoint = new Vec2(0, 0);
        let tiledMapSize = this.tiledMap.getMapSize();
        // console.log(tiledMapSize);
        // console.log(tiledSize);
        // 这里基于Tiledmap地图像素宽高的一半做的偏移回正，为了使碰撞体组件在正确位置添加
        // 但是注意AnchorPoint属性会影响节点UITransform相关位置判断
        // 原理类似于角色和地图边界判断时，要考虑AnchorPoint的影响
        // 如果后续模块复用时出现问题可以排查是否和相关节点的UITransform的AnchorPoint有关
        let tiledMapHalfWidth = tiledMapSize.width * tiledSize.width / 2;
        let tiledMapHalfHeight = tiledMapSize.height * tiledSize.height / 2;
        let newX = layer.node.position.x - tiledMapHalfWidth;
        let newY = layer.node.position.y - tiledMapHalfHeight;
        layer.node.setPosition(newX, newY);


        // 另一套基于中心点偏移的矫正Tiledmap地图层级节点位置，为了使碰撞体组在正确位置添加
        // const [newX , newY] = [layer.leftDownToCenterX, layer.leftDownToCenterY];
        // const layerUITransform = layer.node.getComponent(UITransform);
        // layerUITransform.anchorPoint = new Vec2(0, 0);
        // // console.log(tiledMapSize);
        // // console.log(tiledSize);       
        // layer.node.setPosition(-newX, -newY);


        //生成父节点预制体碰撞体组暂时在引擎内编辑在一个父节点里修改位置(-tiledMapHalfWidth, -tiledMapHalfHeight)，在赋给对应层级。
        //由于对Tiledmap中的Tiledtile节点是完全黑盒的，修改位置会出问题，所以添加碰撞体父节点功能暂时取消。日志时间：2025.08.13
        //在层级中生成一个子节点作为该层级下所有子节点的父节点
        // let collisionNode = new Node('CollisionNode');
        // //经过测试，层级下子节点CollisionNode所有碰撞体父节点，要把位置改为(-tiledMapHalfWidth, -tiledMapHalfHeight)，碰撞体位置才正确。
        // //类似要矫正层级节点位置一样的原理，但是由于后面获取的tiled节点里面的TiledTile信息是黑盒，setPosition修改位置会报无法解决的错误暂时搁置
        // collisionNode.setPosition(-tiledMapHalfWidth, -tiledMapHalfHeight);
        // collisionNode.addComponent(UITransform);
        // collisionNode.setParent(layer.node);

        for (let i = 0; i < layerSize.width; i++) {

            for (let j = 0; j < layerSize.height; j++) {
                const exsit = layer.getTileGIDAt(i, j);
                if (exsit != 0) {
                    let tiled = layer.getTiledTileAt(i, j, true);

                    //这里RigidBody设置类型有关代码有待确认是否正确
                    // let body = tiled.node.addComponent(RigidBody2D);
                    // body.type = 0;
                    let body = tiled.node.addComponent(RigidBody);
                    body.type = RigidBody.Type.STATIC;
                    //添加碰撞盒
                    let collider = tiled.node.addComponent(BoxCollider2D);
                    //将碰撞体分组设置为4，即项目物理设置中分组Index值为2即Wall的分组
                    //注意因为截止到3.8.6版本，Tiledmap整张地图只能统一添加为一种碰撞组，不支持按层分组
                    //所以后续整理碰撞分组，Tiledmap地图相关碰撞都设置为障碍物分组
                    collider.group = 4;
                    //因为通过上面getTiledTileAt()生成逻辑是将左下角作为生成锚点。
                    //直接生成碰撞体会将左下角作为碰撞体的中心点添加碰撞体与目标位置不吻合
                    //所以设置碰撞体位置偏移量要向右上偏移tile块像素大小宽高的一半
                    collider.offset = new Vec2(tiledSize.width / 2, tiledSize.height / 2);
                    collider.size = tiledSize;
                    collider.apply();






                    //由于对Tiledmap中的Tiledtile节点是完全黑盒的，修改位置会出问题，所以添加碰撞体父节点功能暂时取消。日志时间：2025.08.13
                    // //将生成的tiled节点修改父节点到一个单独节点中方便拖拽成为预制体
                    // tiled.node.removeFromParent();
                    // //计算节点在世界坐标系中的位置
                    // let tiledUITransform = tiled.node.getComponent(UITransform);
                    // let worldPosition = tiledUITransform.convertToWorldSpaceAR(Vec3.ZERO);
                    // //将节点设置为新的父节点
                    // tiled.node.setParent(collisionNode);
                    // //根据之前计算的世界坐标位置，重新设置节点位置
                    // let collisionNodeUITransfrom = collisionNode.getComponent(UITransform);                   
                    // tiled.node.setPosition(collisionNodeUITransfrom.convertToWorldSpaceAR(worldPosition));



                }
            }
        }
    }



}


